/*
 * Fichier principal
 */


#include "parseur/XML/Balise.h"
#include "parseur/DTD/tree/DtdTree.h"
#include "parseur/XSL/XSLEngine.h"
#include "parseur/XSL/XSLStylesheet.h"
#include "parseur/Validator/DtdValidator.h"

// TODO : enlever
#include "parseur/testSamples.h"

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>


using namespace std;


/* Constantes */
#define NB_PARAMETERS 7
#define XML_OPT "-xml"
#define DTD_OPT "-dtd"
#define XSL_OPT "-xsl"



int dtd_parse(DtdTree **dtdDoc);
int xml_parse(char** dtdPath, Balise **docRoot);
extern FILE* xml_in;
extern FILE* dtd_in;

bool openFile(int argc, char **argv, Balise ** xmlDoc, DtdTree **dtdDoc,
	Balise **xslDoc)
{
	string paths[3];	/* 0 : xml
						 * 1 : xsl
						 * 2 : dtd
						 */
	const char *files[] = {"XML", "XSL", "DTD"};

	if (argc != NB_PARAMETERS)
	{
		cerr << "NOMBRE DE PARAMÈTRES INCORRECTS" << endl;
		cerr << "arguments attendus: -xml, -dtd - xls" << endl;
		return false;
	}

	int p;
	for (int i = 1; i < NB_PARAMETERS; i++)
	{
		if ((i & 1) == 1)
		{ // On attend une option
			if (strcmp(argv[i], XML_OPT) == 0)
			{
				p = 0;
			}
			else if (strcmp(argv[i], XSL_OPT) == 0)
			{
				p = 1;
			}
			else if (strcmp(argv[i], DTD_OPT) == 0)
			{
				p = 2;
			}
			else
			{
				cerr << "Option : " << argv[i] << " invalide." << endl;
				return false;
			}
		}
		else
		{
			paths[p] = argv[i];
		}
	}

	for (int i = 0; i < 3; i++)
	{
		if (paths[i].empty())
		{
			cerr << "Ils manque le fichier " << files[i] << endl;
			return false;
		}
	}

	/* Parsing des fichiers */
	xml_in = fopen(paths[0].c_str(),"r");
	if (!xml_in)
	{
		cerr << ">> Erreur à l'ouverture du fichier XML" << endl;
		return false;
	}	
	char *dtdPath;
	if (xml_parse(&dtdPath, xmlDoc) != 0)
	{
		cerr << ">> Erreur lors du parsing du fichier XML" << endl;
		return false;
	}
	fclose(xml_in);

	if (dtdPath != NULL)
	{
		/*
		FILE * dtd_in = fopen(paths[2].c_str(), "r");
		if (!dtd_in)
		{
			cerr << ">> Erreur à l'ouverture du fichier DTD" << endl;
			return false;
		}
		cout << ">> parsing du DTD " << paths[2] << endl;
		if (dtd_parse(dtdDoc) != 0)
		{
			cerr << ">> Erreur lors du parsing du DTD" << endl;
			return false;
		}
		cout << "parsing done" << endl;
		fclose(dtd_in);
		*/
	}

	*dtdDoc = generateDtd();

	/*
	xml_in = fopen(paths[1].c_str(),"r");
	if (!xml_in)
	{
		cerr << ">> Erreur à l'ouverture du fichier XSL" << endl;
		return false;
	}	
	if (xml_parse(&dtdPath, xslDoc) != 0)
	{
		cerr << ">> Erreur lors du parsing du fichier XSL" << endl;
		return false;
	}
	fclose(xml_in);
	*/

	*xslDoc = generateXSL();

	return true;
}


/*
 * Choix que peut faire l'utilisateur
 */
#define QUIT      0
#define PRINT_XML 1
#define PRINT_DTD 2
#define PRINT_XSL 3
#define VALID_XML 4
#define APPLY_XSL 5
#define PRINT_HTM 6

int askUser( )
{
	int ch;
	cout << endl;
	cout << "-----------------------------------------------------------------------" << endl;
	cout << "* 1 Afficher le fichier XML" << endl;
	cout << "* 2 Afficher le fichier DTD" << endl;
	cout << "* 3 Afficher le fichier XSL" << endl;
	cout << "* 4 Valider le XML avec le DTD" << endl;
	cout << "* 5 Transformer le XML avec le XSL" << endl;
	cout << "* 6 Afficher le XML transformé" << endl;
	cout << "* 0 Quitter" << endl;
	cout << "-----------------------------------------------------------------------" << endl;
	cout << "> "; cin >> ch;

	return ch;
}

void sayByeBye() {
	cout << " _____ .                    ______  _______      ______  _______ _______ _     _" << endl;
	cout << "   |   ' |      |           |_____] |______      |_____] |_____| |       |____/ " << endl;
	cout << " __|__   |_____ |_____      |_____] |______      |_____] |     | |_____  |    \\_" << endl;
	cout << "                                                                                " << endl;
}

int main(int argc, char **argv)
{
	Balise *xmlDoc = NULL;
	DtdTree *dtdDoc;
	Balise *xslDoc = NULL;
	Balise *transDoc = NULL;

	dtdDoc = new DtdTree();

	if (!openFile(argc, argv, &xmlDoc, &dtdDoc, &xslDoc))
	{
		return 1;
	}
	cout << ">> Fichiers XML , DTD et XSL ouverts..." << endl << endl;

	DtdValidator dtdVal(xmlDoc, dtdDoc);
	XSLStylesheet xslSs(xslDoc);
	XSLEngine xslEng(&xslSs, xmlDoc);
	bool xslComputed = false;

	int ch;
	while ((ch = askUser()) != QUIT)
	{
		if (ch == PRINT_XML)
		{
			cout << endl << xmlDoc->toString(1) << endl << endl;
		}
		else if (ch == PRINT_DTD)
		{
			if (dtdDoc != NULL)
			{
				cout << endl << dtdDoc->getDtdAsString() << endl << endl;
			}
			else
			{
				cout << endl << ">> Pas de DTD" << endl << endl;
			}
		}
		else if (ch == PRINT_XSL)
		{
			cout << endl << xslDoc->toString(1) << endl << endl;
		}
		else if (ch == VALID_XML)
		{
			bool dtdValidated = dtdVal.isValid();
			if (dtdValidated)
			{
				cout << ">> DTD validé" <<  endl << endl;
			}
			else
			{
				cout << ">> DTD invalide :( pour les raisons suivantes: " << endl;
				cout << dtdVal.getErrMsg() << endl << endl;
			}
		}
		else if (ch == APPLY_XSL)
		{
			if (transDoc != NULL) 
					delete transDoc;

			xslComputed = xslEng.transformXMLDoc();
			if (xslComputed)
			{
				transDoc = xslEng.getTransformedXMLDoc();
				cout << ">> Transformation XSL appliqué au XML" << endl << endl;
			}
			else
			{
				transDoc = NULL;
				cout << ">> Echec de la transformation XSL :( pour les raisons suivantes :" << endl;
				cout << xslEng.getErrMsg() << endl << endl;
			}
		}
		else if (ch == PRINT_HTM)
		{
			if (xslComputed && transDoc != NULL)
			{
				cout << endl << transDoc->toString(1) << endl << endl;
			}
			else
			{
				cout << ">> Transformez le doc avant de l'afficher !" << endl << endl;
			}
		}
		else
		{
			cerr << ">> Choix invalide" << endl << endl;
		}
	}


	if (xmlDoc != NULL) 
		delete xmlDoc;
	if (dtdDoc != NULL)
		delete dtdDoc;
	if (xslDoc != NULL)
		delete xslDoc;
	if (transDoc != NULL)
		delete transDoc;

	//just for fun
	sayByeBye();

	return 0;
}
